<?php
/*****************************************************
 * File name: BaseFunction.php
 * Create date: 2017/10/12
 * Author: smallyang
 * Description: 常用的函数
 *****************************************************/

if (!function_exists('checkOpenid')) {
    /**
     * 检测openid
     *
     * @param $openid string openId
     * @param $type string openId类型
     * @return bool 成功匹配状态
     */
    function checkOpenid($openid, $type = '')
    {
        if (empty($openid)) {
            return false;
        }

        if ($type == 'qq') {
            $reg = '/^[0-9A-Z]{32}$/';
        } else if ($type == 'wx') {
            $reg = '/^[\dA-Za-z-_]{28,64}$/';
        } else {
            $reg = '/^[\dA-Za-z-_]{28,64}$/';
        }

        return preg_match($reg, $openid);
    }
}

if (!function_exists('UTF8toGBK')) {

    /**
     * UTF8toGB2312
     *
     * @param $str string 需要转换的utf8字符串或数组
     * @return string 转成gbk后的字符串或数组
     */
    function UTF8toGBK($str)
    {
        if (is_array($str)) {
            foreach ($str as &$value) {
                $value = UTF8toGBK($value);
            }
            return $str;
        } elseif (is_string($str)) {
            $str = iconv("UTF-8", "GBK//IGNORE", $str);
            return $str;
        } else {
            return $str;
        }
    }
}

if (!function_exists('GBKtoUTF8')) {

    /**
     * GB2312toUTF8
     *
     * @param $str string 需要转换的gbk字符串或数组
     * @return string 转成utf8后的字符串或数组
     */
    function GBKtoUTF8($str)
    {
        if (is_array($str)) {
            foreach ($str as &$value) {
                $value = GBKtoUTF8($value);
            }
            return $str;
        } elseif (is_string($str)) {
            $str = iconv("GBK", "UTF-8//IGNORE", $str);
            return $str;
        } else {
            return $str;
        }
    }
}

if (!function_exists('getRealIp')) {

    /**
     * 获取真实的IP
     *
     * @return string
     */
    function getRealIp()
    {
        if (isset($_SERVER)) {
            if (isset($_SERVER['HTTP_X_FORWARDED_FOR'])) {
                $arr = explode(',', $_SERVER['HTTP_X_FORWARDED_FOR']);

                foreach ($arr as $ip) {
                    $ip = trim($ip);

                    if ($ip != 'unknown') {
                        $realip = $ip;

                        break;
                    }
                }
            } elseif (isset($_SERVER['HTTP_CLIENT_IP'])) {
                $realip = $_SERVER['HTTP_CLIENT_IP'];
            } else {
                if (isset($_SERVER['REMOTE_ADDR'])) {
                    $realip = $_SERVER['REMOTE_ADDR'];
                } else {
                    $realip = '0.0.0.0';
                }
            }
        } else {
            if (getenv('HTTP_X_FORWARDED_FOR')) {
                $realip = getenv('HTTP_X_FORWARDED_FOR');
            } elseif (getenv('HTTP_CLIENT_IP')) {
                $realip = getenv('HTTP_CLIENT_IP');
            } else {
                $realip = getenv('REMOTE_ADDR');
            }
        }

        preg_match("/[\d\.]{7,15}/", $realip, $onlineip);
        $realip = !empty($onlineip[0]) ? $onlineip[0] : '0.0.0.0';

        return $realip;
    }
}

if (!function_exists('injectCheck')) {

    /**
     * 检测sql关键字
     *
     * @param $str string sql
     * @return int
     */
    function injectCheck($str)
    {
        return preg_replace("/select|insert|update|delete|drop|\'|\/\*|\*|\+|\-|\"|\.\.\/|\.\/|union|into|load_file|outfile|dump/is", '', $str);
    }
}

if (!function_exists('recordAMSLog')) {

    /**
     * ams日志记录
     *
     * @param $logInfo string 需要记录的日志
     * @return null
     */
    function recordAMSLog($logInfo)
    {
        //测试
        if (ENV == 'test' && ENVIRONMENT == 'NON_OA') {
            $time = date('Ymd');
            file_put_contents(APP . 'logs/' . $time . '.log', date('Y-m-d H:i:s') . ' ---- ' . $logInfo . PHP_EOL, FILE_APPEND);
        } else {
            //流水号
            if (!isset($_GET["iAmsActivityId"])) {
                $_GET["iAmsActivityId"] = 208380;
            }

            $sAmsSerial = $_GET["sAmsSerial"];
            if (!isset($sAmsSerial)) {
                $sAmsSerial = $_GET["sAmsSerial"] = createAmsSerial();
            }

            if ($_GET["iAmsActivityId"] != "") {
                $obj = new \Logger(null);
                $logInfo = UTF8toGBK($logInfo);
                $obj->writePlatLog(__FILE__, __LINE__, LP_INFO, $_GET["iAmsActivityId"], "AMS", "[$sAmsSerial][Condition] " . $logInfo . "\n");
            }
        }
    }
}

if (!function_exists('saveUploadedFile')) {

    /**
     * 保存前端通过表单上传的文件指定的地方
     *
     * @param $folder string 文件保存的目录
     * @return mixed
     *
     *  2019-04-09 xiangangwei 支持批量上床文件以及文件保存的文件夹
     */
    function saveUploadedFile($folder = '')
    {
        //测试
        $successSaved = array();

        if (empty($folder)) {
            recordAMSLog(__FILE__ . "," . __LINE__ . ' does not assign the save folder');
            return false;
        }

       foreach ($_FILES as $key => $file){
           recordAMSLog(__FILE__ . "," . __LINE__ . 'upload file info: '.json_encode($file));
           $tmpName = $file['tmp_name'];
           $size = $file['size'];
           $type = explode('/',$file['type'])[1];
           // 如果没有指定文件名就使用本地文件的名字
           $fileName = empty($name) ? $file['name']: $name;

           if (ENV == 'test' && ENVIRONMENT == 'NON_OA') {
               $savePath = APP.'upload/'.$folder.'/'.$fileName;
           } else {
               $savePath = APP.UPLOADED_PATH.$folder.'/'.$fileName;
           }

           recordAMSLog(__FILE__ . "," . __LINE__ . "fileName: $fileName savePath: $savePath");

           if ( $size > MAX_UPLOAD_SIZE*1024*1024 ) {
               recordAMSLog(__FILE__ . "," . __LINE__ . 'uploaded file oversizes the limit '.MAX_UPLOAD_SIZE.'MB');

           }
           if (!in_array($type,ALLOW_TYPE)){
               recordAMSLog(__FILE__ . "," . __LINE__ . 'uploaded file is not in the allow types');
           }

           if (save($tmpName, $savePath)) {
               $successSaved[] = $savePath;
               recordAMSLog(__FILE__ . "," . __LINE__ . 'save upload file success at '.$savePath);
           } else {
               recordAMSLog(__FILE__ . "," . __LINE__ . 'save upload file failed');
           }
       }

       if (count($successSaved) > 0) {
           return $successSaved;
       } else {
           return false;
       }

    }
}
if (!function_exists('logWrite')) {
    /**
     * 操作日志
     * @param int $type 操作类型 1：新增；2：更新：3：删除；4：登陆；5：其他
     * @param bool $res 操作结果 true：成功 false:失败
     * @param string $table 数据表 数据操作需要传这个参数
     * @param string $action 事件类型
     */
    function logWrite($type = 5, $res = false, $table = '',$action = null)
    {
        $ctrl = new Lib\Base\Ctrl();
        $db = Lib\Db\DbModel::init();
        $user = new Lib\Paas\Login();
        switch ($type) {
            case $ctrl::LOG_TYPE_INSENT:
                $log['type'] = $ctrl::LOG_TYPE_INSENT;
                $log['action'] = $action?$action:"新增";
                $log['sql'] = $db->getLastSql();
                break;
            case $ctrl::LOG_TYPE_EDIT;
                $log['type'] = $ctrl::LOG_TYPE_EDIT;
                $log['action'] = $action?$action:"编辑";
                $log['sql'] = $db->getLastSql();
                break;
            case $ctrl::LOG_TYPE_DEL;
                $log['type'] = $ctrl::LOG_TYPE_DEL;
                $log['action'] = $action?$action:"删除";
                $log['sql'] = $db->getLastSql();
                break;
            case $ctrl::LOG_TYPE_LOGIN;
                $log['type'] = $ctrl::LOG_TYPE_LOGIN;
                $log['action'] = $action?$action:"登陆";
                break;
            case $ctrl::LOG_TYPE_OTHER;
                $log['type'] = $ctrl::LOG_TYPE_OTHER;
                $log['action'] = $action?$action:"其他";
                if(!empty($table)){
                    $log['sql'] = $db->getLastSql();
                }
                break;
            case $ctrl::LOG_TYPE_JSON_UPLOAD;
                $log['type'] = $ctrl::LOG_TYPE_JSON_UPLOAD;
                $log['action'] = $action?$action:"导入";
                if(!empty($table)){
                    $log['sql'] = $db->getLastSql();
                }
                break;
            default:
                $log['type'] = $ctrl::LOG_TYPE_OTHER;
                $log['action'] = $action?$action:"其他";
                if(!empty($table)){
                    $log['sql'] = $db->getLastSql();
                }
                break;
        }

        $userInfo = $user->getLoginInfo();
        $log['name'] = $userInfo['name'];
        $log['url'] = $_SERVER['REQUEST_URI'];
        $log['table'] = $table;
        $log['result'] = $res ? "执行成功" : "执行失败";
        $log['createTime'] = date("Y-m-d H:i:s", time());
        $log['sql'] = str_replace("'",'"',outportFilter($log['sql']));//避免数据库写入时多次转义
        $log['sSerial'] = $_GET['sAmsSerial'];//流水号
        $res = $db->table('tblog')->insert($log);
        if (!$res) {
            recordAMSLog(__FILE__ . "," . __LINE__ . ",添加日志失败,data:" . var_export($log, true));
        }
    }
}

/**
 * 保存上传的文件
 *
 * @param $tmpName
 * @param $savePath
 * @return bool
 */
function save($tmpName, $savePath) {
    $pathParts = pathinfo($savePath);
    if (!is_dir($pathParts['dirname'])) {
        mkdir($pathParts['dirname']);
    }
    return move_uploaded_file($tmpName, $savePath);
}

/**
 * 输出json
 *
 * @param $iRetcode int 状态码
 * @param $sErrorMsg string 状态说明
 * @param $vmResult array 返回的数组
 * @return string json
 */
function outputJSON($iRetcode = 0, $sErrorMsg = 'ok', $vmResult = array())
{
    $res = array(
        'iRet' => $iRetcode,
        'sMsg' => $sErrorMsg,
        'jData' => $vmResult,
        'sSerial' => $_GET["sAmsSerial"],
    );
    recordAMSLog(__FILE__ . "," . __LINE__ . ",output data(before filterHtml):" . var_export($res, true));
    $res = Lib\Base\Common::filterHtml($res);
    recordAMSLog(__FILE__ . "," . __LINE__ . ",output data(after filterHtml):" . var_export($res, true));
    echo json_encode($res);

    //echo UTF8toGBK($r);

    exit();
}

/**
 * 生成随机数
 *
 * @param int $len
 * @return string
 */
function getRandStr($len = 6)
{
    $chars = 'ABDEFGHJKLMNPQRSTVWXYabdefghijkmnpqrstvwxy23456789';
    $password = '';
    while (strlen($password) < $len) {
        $password .= substr($chars, (mt_rand() % strlen($chars)), 1);
    }
    return $password;
}

/**
 * 生成AmsSerial流水
 *
 * @param $sServiceType
 * @param $iAmsActivityId
 * @return string
 */
function createAmsSerial($sServiceType = 'LOL', $iAmsActivityId = 208380)
{
    $str = 'AMS-' . $sServiceType . '-' . strftime('%m%d%H%M%S') . '-' . getRandStr();
    $str .= '-' . $iAmsActivityId . '-' . mt_rand(100000, 999999);
    return $str;
}

/**
 * @param $className
 */
function registerNamespace($className)
{
    if (strpos($className, 'Lib') !== false && ENV != 'test') {
        $fileName = dirname(LIB_PATH) . '/' . str_replace('\\', DIRECTORY_SEPARATOR, ucwords($className, '\\')) . '.php';
    } else {
        $fileName = APP . str_replace('\\', DIRECTORY_SEPARATOR, ucwords($className, '\\')) . '.php';
    }

    if (is_file($fileName)) {
        require_once $fileName;
    } else {
        outputJSON(-101, $fileName . '文件不存在');
    }
}


/**
 * 将读取到的目录以数组的形式展现出来
 * @return array
 * opendir() 函数打开一个目录句柄，可由 closedir()，readdir() 和 rewinddir() 使用。
 * is_dir() 函数检查指定的文件是否是目录。
 * readdir() 函数返回由 opendir() 打开的目录句柄中的条目。
 * @param array $files 所有的文件条目的存放数组
 * @param string $file 返回的文件条目
 * @param string $dir 文件的路径
 * @param resource $handle 打开的文件目录句柄
 */
function my_scandir($dir)
{
    //定义一个数组
    $files = array();
    //检测是否存在文件
    if (is_dir($dir)) {
        //打开目录
        if ($handle = opendir($dir)) {
            //返回当前文件的条目
            while (($file = readdir($handle)) !== false) {
                //去除特殊目录
                if ($file != "." && $file != "..") {
                    //判断子目录是否还存在子目录
                    if (is_dir($dir . "/" . $file)) {
                        //递归调用本函数，再次获取目录
                        $files[$file] = my_scandir($dir . "/" . $file);
                    } else {
                        //获取目录数组
                        $files[] = $dir . "/" . $file;
                    }
                }
            }
            //关闭文件夹
            closedir($handle);
            //返回文件夹数组
            return $files;
        }
    }
}

/**
 * 获取文件夹的内容
 * @param  dir 文件夹路径
 */
function read_all_file($dir){
    if (!is_dir($dir)) {
        recordAMSLog(__FILE__ . "," . __LINE__ . ",{$dir} 不是一个目录！");
    }
    static $result = array();
    $handle = opendir($dir);
    if($handle){
        while(($file = readdir($handle)) !== false){
            if($file != '.' && $file != '..'){
                $file = mb_convert_encoding($file,"UTF-8","gb2312");
                $cur_path = $dir .'/'. $file;
                if (is_dir($cur_path)){
                    read_all_file($cur_path);
                }else{
                    $result[] = $dir .'/'. $file;
                }
            }
        }
        closedir($handle);
    }
    return $result;
}

/**
 * 剪切目录
 * @param $strSrcDir 开始目录
 * @param $strDstDir 目标目录
 * @return bool
 */
function copydir($strSrcDir, $strDstDir)
{
    $dir = opendir($strSrcDir);
    if (!$dir) {
        return false;
    }
    if (!is_dir($strDstDir)) {
        if (!mkdir($strDstDir)) {
            return false;
        }
    }
    while (false !== ($file = readdir($dir))) {
        if (($file!='.') && ($file!='..')) {
            if (is_dir($strSrcDir.'/'.$file) ) {
                if (!copydir($strSrcDir.'/'.$file, $strDstDir.'/'.$file)) {
                    return false;
                }
            } else {
                if (!copy($strSrcDir.'/'.$file, $strDstDir.'/'.$file)) {
                    return false;
                }
            }
        }
    }
    closedir($dir);
    return true;
}

/**
 * 删除目录及目录下所有的文件
 * @param $dir
 * @return bool
 */
function deleteDir($dir)
{
    if (!$handle = @opendir($dir)) {
        return false;
    }
    while (false !== ($file = readdir($handle))) {
        if ($file !== "." && $file !== "..") {       //排除当前目录与父级目录
            $file = $dir . '/' . $file;
            if (is_dir($file)) {
                deleteDir($file);
            } else {
                @unlink($file);
            }
        }

    }
    closedir($dir);
    rmdir($dir);
}

//注册namespace加载类
spl_autoload_register('registerNamespace');


/**
 * 安全过滤
 * @param $value
 */
function lol_filter(&$value)
{
    // TODO 其他安全过滤
    //return preg_replace("/select|insert|update|delete|drop|\'|\/\*|\*|\+|\-|\"|\.\.\/|\.\/|union|into|load_file|outfile|dump/is", '', $str);
    //$value = injectCheck($value);
    $value = preg_replace("/select |insert |update |delete |drop |union |into |load_file |outfile | dump| sheep/is", '', $value);

    //其他数据库操作敏感字符
    $value = preg_replace("/UPDATEXML |EXEC | MASTER |TRUNCATE |DECLARE |CREATE /is", '', $value);

    //查询条件敏感字符 EXP|NEQ|GT|EGT|LT|ELT|OR|XOR|LIKE|NOTLIKE|NOT BETWEEN|NOTBETWEEN|BETWEEN|NOTIN|NOT IN|IN
    $value = preg_replace("/ EXP | NOTLIKE | NOT BETWEEN | NOTBETWEEN | NOTIN | NOT IN /is", '', $value);

    $value = preg_replace("/ CONTACT |EXTRACTVALUE |INFORMATION_SCHEMA |%20/is", '', $value);

}

/**
 * xss漏洞
 * @param $val
 * @return null|string|string[]
 */
function removeXSS($val)
{
    // remove all non-printable characters. CR(0a) and LF(0b) and TAB(9) are allowed
    // this prevents some character re-spacing such as <java\0script>
    // note that you have to handle splits with \n, \r, and \t later since they *are* allowed in some inputs
    $val = preg_replace('/([\x00-\x08,\x0b-\x0c,\x0e-\x19])/', '', $val);

    // straight replacements, the user should never need these since they're normal characters
    // this prevents like <IMG SRC=@avascript:alert('XSS')>
    $search = 'abcdefghijklmnopqrstuvwxyz';
    $search .= 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
    $search .= '1234567890!@#$%^&*()';
    $search .= '~`";:?+/={}[]-_|\'\\';
    for ($i = 0; $i < strlen($search); $i++) {
        // ;? matches the ;, which is optional
        // 0{0,7} matches any padded zeros, which are optional and go up to 8 chars

        // @ @ search for the hex values
        $val = preg_replace('/(&#[xX]0{0,8}' . dechex(ord($search[$i])) . ';?)/i', $search[$i], $val); // with a ;
        // @ @ 0{0,7} matches '0' zero to seven times
        $val = preg_replace('/(&#0{0,8}' . ord($search[$i]) . ';?)/', $search[$i], $val); // with a ;
    }

    // now the only remaining whitespace attacks are \t, \n, and \r
    $ra1 = Array(
        'javascript',
        'vbscript',
        'expression',
        'applet',
        'meta',
        'xml',
        'blink',
        'link',
        'style',
        'script',
        'embed',
        'object',
        'iframe',
        'frame',
        'frameset',
        'ilayer',
        'layer',
        'bgsound',
        'title',
        'base'
    );
    $ra2 = Array(
        'onabort',
        'onactivate',
        'onafterprint',
        'onafterupdate',
        'onbeforeactivate',
        'onbeforecopy',
        'onbeforecut',
        'onbeforedeactivate',
        'onbeforeeditfocus',
        'onbeforepaste',
        'onbeforeprint',
        'onbeforeunload',
        'onbeforeupdate',
        'onblur',
        'onbounce',
        'oncellchange',
        'onchange',
        'onclick',
        'oncontextmenu',
        'oncontrolselect',
        'oncopy',
        'oncut',
        'ondataavailable',
        'ondatasetchanged',
        'ondatasetcomplete',
        'ondblclick',
        'ondeactivate',
        'ondrag',
        'ondragend',
        'ondragenter',
        'ondragleave',
        'ondragover',
        'ondragstart',
        'ondrop',
        'onerror',
        'onerrorupdate',
        'onfilterchange',
        'onfinish',
        'onfocus',
        'onfocusin',
        'onfocusout',
        'onhelp',
        'onkeydown',
        'onkeypress',
        'onkeyup',
        'onlayoutcomplete',
        'onload',
        'onlosecapture',
        'onmousedown',
        'onmouseenter',
        'onmouseleave',
        'onmousemove',
        'onmouseout',
        'onmouseover',
        'onmouseup',
        'onmousewheel',
        'onmove',
        'onmoveend',
        'onmovestart',
        'onpaste',
        'onpropertychange',
        'onreadystatechange',
        'onreset',
        'onresize',
        'onresizeend',
        'onresizestart',
        'onrowenter',
        'onrowexit',
        'onrowsdelete',
        'onrowsinserted',
        'onscroll',
        'onselect',
        'onselectionchange',
        'onselectstart',
        'onstart',
        'onstop',
        'onsubmit',
        'onunload'
    );
    $ra = array_merge($ra1, $ra2);

    $found = true; // keep replacing as long as the previous round replaced something
    while ($found == true) {
        $val_before = $val;
        for ($i = 0; $i < sizeof($ra); $i++) {
            $pattern = '/';
            for ($j = 0; $j < strlen($ra[$i]); $j++) {
                if ($j > 0) {
                    $pattern .= '(';
                    $pattern .= '(&#[xX]0{0,8}([9ab]);)';
                    $pattern .= '|';
                    $pattern .= '|(&#0{0,8}([9|10|13]);)';
                    $pattern .= ')*';
                }
                $pattern .= $ra[$i][$j];
            }
            $pattern .= '/i';
            $replacement = substr($ra[$i], 0, 2) . '<x>' . substr($ra[$i], 2); // add in <> to nerf the tag
            $val = preg_replace($pattern, $replacement, $val); // filter out the hex tags
            if ($val_before == $val) {
                // no replacements were made, so exit the loop
                $found = false;
            }
        }
    }
    //过滤掉javascript关闭和退出操作
    $go_back = array('ja<x>vasc<x>ript:history.back', 'ja<x>vasc<x>ript:window.close');
    $replace_back = array('javascript:history.back', 'javascript:window.close');
    for ($i = 0; $i < sizeof($go_back); $i++) {
        $pattern = '/';
        for ($j = 0; $j < strlen($go_back[$i]); $j++) {
            if ($j > 0) {
                $pattern .= '(';
                $pattern .= '(&#[xX]0{0,8}([9ab]);)';
                $pattern .= '|';
                $pattern .= '|(&#0{0,8}([9|10|13]);)';
                $pattern .= ')*';
            }
            $pattern .= $go_back[$i][$j];
        }
        $pattern .= '/i';
        $val = preg_replace($pattern, $replace_back[$i], $val); // filter out the hex tags
    }
    return $val;
}

function array_map_recursive($filter, $data)
{
    $result = array();
    foreach ($data as $key => $val) {
        $result[$key] = is_array($val) ? array_map_recursive($filter, $val) : call_user_func($filter, $val);
    }
    return $result;
}


/**
 * 获取输入参数 支持过滤和默认值
 * 使用方法:
 * <code>
 * I('id',0); 获取id参数 自动判断get或者post
 * I('post.name','','htmlspecialchars'); 获取$_POST['name']
 * I('get.'); 获取$_GET
 * </code>
 * @param string $name 变量的名称 支持指定类型
 * @param mixed $default 不存在的时候默认值
 * @param mixed $filter 参数过滤方法
 * @param mixed $datas 要获取的额外数据源
 * @return mixed
 */
function I($name, $default = '', $filter = null, $datas = null)
{
    static $_PUT = null;
    if (strpos($name, '/')) { // 指定修饰符
        list($name, $type) = explode('/', $name, 2);
    }
    if (strpos($name, '.')) { // 指定参数来源
        list($method, $name) = explode('.', $name, 2);
    } else { // 默认为自动判断
        $method = 'param';
    }
    switch (strtolower($method)) {
        case 'get'     :
            $input =& $_GET;
            break;
        case 'post'    :
            $input =& $_POST;
            break;
        case 'put'     :
            if (is_null($_PUT)) {
                parse_str(file_get_contents('php://input'), $_PUT);
            }
            $input = $_PUT;
            break;
        case 'param'   :
            switch ($_SERVER['REQUEST_METHOD']) {
                case 'POST':
                    $input = $_POST;
                    break;
                case 'PUT':
                    if (is_null($_PUT)) {
                        parse_str(file_get_contents('php://input'), $_PUT);
                    }
                    $input = $_PUT;
                    break;
                default:
                    $input = $_GET;
            }
            break;
        case 'request' :
            $input =& $_REQUEST;
            break;
        case 'session' :
            $input =& $_SESSION;
            break;
        case 'cookie'  :
            $input =& $_COOKIE;
            break;
        case 'server'  :
            $input =& $_SERVER;
            break;
        case 'globals' :
            $input =& $GLOBALS;
            break;
        case 'data'    :
            $input =& $datas;
            break;
        default:
            return null;
    }
    if ('' == $name) { // 获取全部变量
        $data = $input;
        $filters = isset($filter) ? $filter : DEFAULT_FILTER;
        if ($filters) {
            if (is_string($filters)) {
                $filters = explode(',', $filters);
            }
            foreach ($filters as $filter) {
                $data = array_map_recursive($filter, $data); // 参数过滤
            }
        }
    } elseif (isset($input[$name])) { // 取值操作
        $data = $input[$name];
        $filters = isset($filter) ? $filter : DEFAULT_FILTER;
        if ($filters) {
            if (is_string($filters)) {
                if (0 === strpos($filters, '/')) {
                    if (1 !== preg_match($filters, (string)$data)) {
                        // 支持正则验证
                        return isset($default) ? $default : null;
                    }
                } else {
                    $filters = explode(',', $filters);
                }
            } elseif (is_int($filters)) {
                $filters = array($filters);
            }

            if (is_array($filters)) {
                foreach ($filters as $filter) {
                    if (function_exists($filter)) {
                        $data = is_array($data) ? array_map_recursive($filter, $data) : $filter($data); // 参数过滤
                    } else {
                        $data = filter_var($data, is_int($filter) ? $filter : filter_id($filter));
                        if (false === $data) {
                            return isset($default) ? $default : null;
                        }
                    }
                }
            }
        }
        if (!empty($type)) {
            switch (strtolower($type)) {
                case 'a':    // 数组
                    $data = (array)$data;
                    break;
                case 'd':    // 数字
                    $data = (int)$data;
                    break;
                case 'f':    // 浮点
                    $data = (float)$data;
                    break;
                case 'b':    // 布尔
                    $data = (boolean)$data;
                    break;
                case 's':   // 字符串
                default:
                    $data = (string)$data;
            }
        }
    } else { // 变量默认值
        $data = isset($default) ? $default : null;
    }
    is_array($data) && array_walk_recursive($data, 'lol_filter');
    is_string($data) && lol_filter($data);
    return $data;
}

/**
 * 浏览器友好的变量输出
 * @param mixed $var 变量
 * @param boolean $echo 是否输出 默认为True 如果为false 则返回输出字符串
 * @param string $label 标签 默认为空
 * @param boolean $strict 是否严谨 默认为true
 * @return void|string
 */
function dump($var, $echo = true, $label = null, $strict = true)
{
    $label = ($label === null) ? '' : rtrim($label) . ' ';
    if (!$strict) {
        if (ini_get('html_errors')) {
            $output = print_r($var, true);
            $output = '<pre>' . $label . htmlspecialchars($output, ENT_QUOTES) . '</pre>';
        } else {
            $output = $label . print_r($var, true);
        }
    } else {
        ob_start();
        var_dump($var);
        $output = ob_get_clean();
        if (!extension_loaded('xdebug')) {
            $output = preg_replace('/\]\=\>\n(\s+)/m', '] => ', $output);
            $output = '<pre>' . $label . htmlspecialchars($output, ENT_QUOTES) . '</pre>';
        }
    }
    if ($echo) {
        echo($output);
        return null;
    } else {
        return $output;
    }
}

/**
 * 判断是否SSL协议
 * @return boolean
 */
function is_ssl()
{
    if (isset($_SERVER['HTTPS']) && ('1' == $_SERVER['HTTPS'] || 'on' == strtolower($_SERVER['HTTPS']))) {
        return true;
    } elseif (isset($_SERVER['SERVER_PORT']) && ('443' == $_SERVER['SERVER_PORT'])) {
        return true;
    }
    return false;
}

/**
 * URL组装 支持不同URL模式
 * @param string $url URL表达式，格式：'控制器/操作' or '操作'
 * @param array $vars 传入的参数，支持数组 格式：['name'=>'user','id'=>1]
 * @return string
 */
function U($url = '', $vars = '')
{

    $actId = I('get.iActId', 0, 'intval');

    if (!$actId) {
        recordAMSLog(__FILE__ . "," . __LINE__ . ",活动号错误");
    }
    $url = trim($url);
    if (!empty($url)) {
        $isMatched = preg_match('/^[a-zA-Z0-9\/]+$/', $url, $matches);
        if (!$isMatched) {
            recordAMSLog(__FILE__ . "," . __LINE__ . ",参数错误 url:" . var_export($url, true));
            return '';
        }
        if (strpos($url, '/')) {
            //指定路由
            $routeArr = explode('/', $url);
            $route = $routeArr[0] . '/' . $routeArr[1];
            recordAMSLog(__FILE__ . "," . __LINE__ . ",ctrl:" . var_export($routeArr[0], true) . ",action:" . var_export($routeArr[1], true));
        } else {
            $route = CONTROLLER_NAME . '/' . $url;
            recordAMSLog(__FILE__ . "," . __LINE__ . ",ctrl:" . var_export(CONTROLLER_NAME, true) . ",action:" . var_export($url, true));
        }
    } else {
        $route = CONTROLLER_NAME . '/' . ACTION_NAME;
        recordAMSLog(__FILE__ . "," . __LINE__ . ",ctrl:" . var_export(CONTROLLER_NAME, true) . ",action:" . var_export(ACTION_NAME, true));
    }

    //活动id

    $data['iActId'] = $actId;

    if (!empty($vars)) {
        if (is_array($vars)) {
            foreach ($vars as $k => $v) {
                $data[$k] = $v;
            }
        } else {
            recordAMSLog(__FILE__ . "," . __LINE__ . ",参数错误 vars:" . var_export($vars, true));
            return '';
        }
    }
   $baseUrl = (is_ssl() ? 'https://' : 'http://') . $_SERVER['HTTP_HOST'] . '/index.php?';
    //todo lr
    // $baseUrl = (is_ssl() ? 'https://' : 'http://') . 'lol.ied.com/lr' . '/index.php?';
    $url = $baseUrl . 'route=' . $route . '&' . http_build_query($data);

    recordAMSLog(__FILE__ . "," . __LINE__ . ",url:" . var_export($url, true));

    return $url;
}

/**
 * @param $type
 * @return bool|string
 */
function logType($type)
{
    switch ($type){
        case 1:
            return '新增';
            break;
        case 2:
            return '编辑';
            break;
        case 3:
            return '删除';
            break;
        case 4:
            return '登陆';
            break;
        case 5:
            return '其他';
            break;
        case 6:
            return '导入';
            break;
        default:
            return false;
            break;
    }
}

/**
 * @param $data
 * @param int $num
 * @return bool
 * 获取最近三个版本的数据,少于三个版本的做排序
 */
function getDataByVersion($data,$num=3)
{
    if(!is_array($data)){
        return false;
    }

    $num = count($data)>$num ? $num : count($data);

    for ($i=0;$i<$num;$i++){
        $version = $data[0]['versionNumber'];

        $k = 0;

        for ($j=1;$j<count($data);$j++){
            if (version_compare($data[$j]['versionNumber'],$version,'gt') === true){
                $version = $data[$j]['versionNumber'];
                $k = $j;
            }
        }

        $arr[] = $data[$k];
        unset($data[$k]);
        $data = array_values($data);
    }

    return $arr;
}

/**
 * 获取皮肤类型
 * @param $key
 * @return mixed|string
 */
function getSkinTypeVal($key,$chinese=false,$all=false)
{
    $showType = [
        'base' => "经典",
        'common' => "普通",
        "Epic" => "史诗",
        "Warrior" => "勇士",
        "Legend" => "传说",
        "Emperor" => "王者",
        "Treasures" => "典藏",
        "myth" => "神话",
        "Ultimate" => "终极",
        "Limited" => "限定",
    ];

    $editType = [
        'base' => [
            "base" => "经典",
        ],
        'common' => [
            "common" => "普通",
        ],
        'Epic' => [
            "Epic" => "史诗",
        ],
        'Warrior' => [
            "Warrior" => "勇士",
        ],
        "Legend" => [
            "Legend" => "传说",
            "LPL" => "职业联赛专属",
            "Superior Warrior" => "超越勇者专属",
        ],
        "Emperor" => [
            "Emperor" => "王者",
        ],
        "Treasures" => [
            "Treasures" => "典藏",
        ],
        "myth" => [
            "Prestige" => "至臻豪华",
            "Hextech Limited" => "海克斯限定",
            "Kindness of the Guardian" => "守护者的善良",
            "glory of the summit" => "巅峰的荣耀",
        ],
        "Ultimate" => [
            "Ultimate" => "终极",
//            "Ultimate（transparent）" => "终极（透明）",
        ],
        "Limited" => [
            "Limited" => "限定",
            "QQ Blue Diamond" => "蓝钻贵族限定版",
            "QQ Club" => "QQ会员限定",
            "TGC" => "TGC限定",
            "TGA" => "TGA限定",
            "PC Bang Championship" => "网吧冠军",
            "PC Bang Prime" => "网吧特权限定",
            "Valentine" => "情人节限定",
            "Snowdown" => "冰雪节限定",
            "Halloween_a" => "万圣节a",
            "Halloween_b (Limited)" => "万圣节b (万圣节限定)",
            "Year of the Monkey" => "猴年限定",
            "Year of the Dragon" => "龙年限定",
            "Year of the Horse" => "马年限定",
            "Year of the Goat" => "羊年限定",
            "Year of the Snake" => "蛇年限定",
            "MSI" => "MSI专属",
            "the City Hero" => "城市英雄",
            "Nvidia" => "英伟达专属",
            "Last Hit" => "补刀大神",
            "Razer" => "雷蛇",
            "Glory of Justice" => "正义的荣耀",
            "Glory of Harbinger" => "先驱者的荣耀",
            "Dignity of Order" => "守序者的尊严",
            "Vision of Explorer" => "探索者的遠見",
            "Wisdom of Pioneer" => "开拓者的卓识",
            "1 Year Celebration" => "1周年",
            "2 Year Celebration" => "2周年",
            "3 Year Celebration" => "3周年",
            "4 Year Celebration" => "4周年",
            "5 Year Celebration" => "5周年",
            "Killer" => "杀敌大神",
            "Demacia Camp" => "德玛西亚训练营",
            "Year of the Rooster" => "雄鸡限定",
            "6 year Celebration" => "6周年",
            "LPL Limited" => "职业联赛限定",
            "Superior Warrior Limited" => "超越勇者限定",
            "Year of the Dog" => "狗年限定",
            "LPL 5th Anniversary" => "LPL5周年限定",
            "7 year Celebration" => "7周年",
            "Year of PIg" => "金猪限定",
        ],
    ];

    //获取所有的类型返回两个数组
    if($all == true){
      $return = [];
      $return['showType'] = $showType;
      $return['editType'] = [];
      foreach ($editType as $type=>$value){
          $return['editType'] = array_merge($return['editType'],$value);
      }
      return $return;
    }

    //1、皮肤汇总获取对应中文
    if($chinese == true){
        foreach ($editType as $type=>$value){
            if (in_array($key, array_keys($value))) {
                return $value[$key];
            }
        }
        return "未找到的type";
    }

    //2、皮肤渲染的时候获取所属的一级分类
    foreach ($editType as $type=>$value){
        if (in_array($key, array_keys($value))) {
            return $type;
        }
    }

    return null;
}

/**
 * 获取皮肤类型
 * @param $key
 * @return mixed|string
 */
function getSkinTypeVal_bak($key,$all=false)
{

    $replaceArr = array(
        'base' => "经典",
        'common' => "普通",
        "Limited" => "限定",
        "QQ Blue Diamond" => "蓝钻贵族限定版",
        "QQ Club" => "QQ会员限定",
        "TGC" => "TGC限定",
        "TGA" => "TGA限定",
        "PC Bang Championship" => "网吧冠军",
        "PC Bang Prime" => "网吧特权限定",
        "Valentine" => "情人节限定",
        "Snowdown" => "冰雪节限定",
        "Halloween_a" => "万圣节a",
        "Halloween_b (Limited)" => "万圣节b (万圣节限定)",
        "Year of the Monkey" => "猴年限定",
        "Year of the Dragon" => "龙年限定",
        "Year of the Horse" => "马年限定",
        "Year of the Goat" => "羊年限定",
        "Year of the Snake" => "蛇年限定",
        "the City Hero" => "城市英雄",
        "Nvidia" => "英伟达专属",
        "Last Hit" => "补刀大神",
        "Razer" => "雷蛇",
        "LPL" => "职业联赛专属",
        "Superior Warrior" => "超越勇者专属",
        "Glory of Justice" => "正义的荣耀",
        "Glory of Harbinger" => "先驱者的荣耀",
        "Dignity of Order" => "守序者的尊严",
        "Vision of Explorer" => "探索者的遠見",
        "Wisdom of Pioneer" => "开拓者的卓识",
        "Epic" => "史诗",
        "Warrior" => "勇士",
        "Legend" => "传说",
        "Emperor" => "王者",
        "Treasures" => "典藏",
        "1 Year Celebration" => "1周年",
        "2 Year Celebration" => "2周年",
        "3 Year Celebration" => "3周年",
        "4 Year Celebration" => "4周年",
        "5 Year Celebration" => "5周年",
        "Killer" => "杀敌大神",
        "Demacia Camp" => "德玛西亚训练营",
        "Year of the Rooster" => "雄鸡限定",
        "6 year Celebration" => "6周年",
        "Hextech Limited" => "海克斯限定",
        "Ultimate（transparent）" => "终极（透明）",
        "LPL Limited" => "职业联赛限定",
        "Superior Warrior Limited" => "超越勇者限定",
        "Year of the Dog" => "狗年限定",
        "LPL 5th Anniversary" => "LPL5周年限定",
        "Kindness of the Guardian" => "守护者的善良",
        "7 year Celebration" => "7周年",
        "Prestige" => "至臻豪华",
        "glory of the summit" => "巅峰的荣耀",
        "Year of PIg" => "金猪限定",
    );

    if ($all == true) {
        //返回所有的皮肤类型
        return $replaceArr;
    } else {
        if (in_array($key, array_keys($replaceArr))) {
            $res = $replaceArr[$key];
        } else {
            $res = "";
        }
        return $res;
    }
}


/**
 * 获取英雄定位中文名
 * @param $key
 * @return mixed|string
 */
function getHeroRolesVal($key)
{
    $replaceArr = array(
        "fighter" => "战士",
        "tank" => "坦克",
        "mage" => "法师",
        "assassin" => "刺客",
        "support" => "辅助",
        "marksman" => "射手",
    );

    if(in_array($key,array_keys($replaceArr))){
        $res = $replaceArr[$key];
    }else{
        $res = "";
    }
    return $res;
}

/**
 * 获取道具地图的中文名称
 * @param $key
 * @return mixed|string
 */
function getItemsMaps($key)
{
    $replaceArr = array(
        "CrystalScar" => "水晶之痕",
        "ProjectSlums" => "次级架构43",
        "SR" => "召唤师峡谷",
        "CityPark" => "瓦洛兰城市乐园",
        "TT" => "扭曲丛林",
        "HA" => "嚎哭深渊",
        "SL" => "未知",
        "Odyssey" => "未知",
    );

    if(in_array($key,array_keys($replaceArr))){
        $res = $replaceArr[$key];
    }else{
        $res = "";
    }
    return $res;
}

/**
 * 获取英雄定位中文名
 * @param $key
 * @return mixed|string
 */
function getHeroRoles($key)
{
    $replaceArr = array(
        "战士" => "fighter",
        "坦克" => "tank",
        "法师" => "mage",
        "刺客" => "assassin",
        "辅助" => "support",
        "射手" => "marksman",
    );

    if(in_array($key,array_keys($replaceArr))){
        $res = $replaceArr[$key];
    }else{
        $res = "";
    }
    return $res;
}

/**
 * 获取英雄阵营
 * @return array
 */
function getHeroCamp()
{
    $res = array(
        '艾欧尼亚',
        '巨神峰',
        '弗雷尔卓德',
        '德玛西亚',
        '恕瑞玛',
        '暗影岛',
        '比尔吉沃特',
        '班德尔城',
        '皮尔特沃夫',
        '祖安',
        '虚空之地',
        '诺克萨斯',
        '符文之地'
    );
    return $res;
}

/**
 * 获取英雄伤害类型
 * @return mixed|string
 */
function getHeroDamageType()
{
    $res = array(
        "kMagic" => '魔法伤害',
        "kPhysical" => '物理伤害',
        "kMixed" => '混合伤害',
    );
    return $res;
}

/**
 * 处理英雄定位问题
 * @param $data
 * @return array|mixed
 */
function heroRoles($data)
{
    $data = $data ?unserialize(outportFilter($data)) : array();


    //定位获取中文
    foreach($data as $key => $val)
    {
        $data[$key] = getHeroRolesVal($val);
    }
    return $data;
}


/**
 * 文件大小格式化
 * @param $size
 * @param string $delimiter
 * @return string
 */
function format_bytes($size, $delimiter = '')
{
    $units = array('b', 'kb', 'mb', 'gb', 'tb', 'pb');
    for ($i = 0; $size >= 1024 && $i < 6; $i++) {
        $size /= 1024;
    }
    return round($size, 2) . $delimiter . $units[$i];
}


/**
 * 递归得到道具所有合成件
 * @param $itemId
 * @param $versionId
 * @param int $pid
 * @return array
 */
function getItemLevel($itemId, $versionId, $pid = 0)
{
    static $items = [];

    $db = Lib\Db\DbModel::init();

    $itemFrom = $db->table('tbitems')->where([
        'itemId' => $itemId,
        'versionId' => $versionId
    ])->find('itemId,`from`,name');

    if($itemFrom){
        $itemFrom['pid'] = $pid;
        $items[] = $itemFrom;

        if (!empty($itemFrom['from'])) {
            $from = unserialize(outportFilter($itemFrom['from']));
            foreach ($from as $val) {
                getItemLevel($val, $versionId, $itemFrom['itemId']);
            }
        }
    }

    return $items;
}

/**
 * 获取道具的合成等级
 * @param $itemId
 * @param $versionId
 * @return int
 */
function getItemLevelNum($itemId, $versionId){
    $db = Lib\Db\DbModel::init();
    $itemFrom = $db->table('tbitems')->where([
        'itemId' => $itemId,
        'versionId' => $versionId
    ])->find('itemId,`from`,name');
    if(empty($itemFrom['from'])){
        recordAMSLog(__FILE__.",".__LINE__.",itemId:".$itemId.",versionId:".$versionId."的道具不存在");
        return 0;
    }else{
        $items = getItemLevel($itemId,$versionId);
        $items = get_column($items,1);
        $level = 0;
        foreach ($items as $k => $v){
            if($v['level'] > $level){
                $level = $v['level'];
            }
        }
        return $level;
    }
}

/**
 * description: 递归菜单
 * @param $array
 * @param int $type 1:顺序菜单 2树状菜单
 * @param int $fid
 * @param int $level
 * @return array
 */
function get_column($array, $type = 1, $fid = 0, $level = 0)
{
    $column = [];
    if ($type == 2) {
        foreach ($array as $key => $vo) {
            if ($vo['pid'] == $fid) {
                $vo['level'] = $level;
                $column[$key] = $vo;
                $column [$key][$vo['itemId']] = get_column($array, $type = 2, $vo['itemId'], $level + 1);
            }
        }
    } else {
        foreach ($array as $key => $vo) {
            if ($vo['pid'] == $fid) {
                $vo['level'] = $level;
                $column[] = $vo;
                $column = array_merge($column, get_column($array, $type = 1, $vo['itemId'], $level + 1));
            }
        }
    }
    return $column;
}

/**
 * 导入json文件时过滤
 * @param $data
 * @return array|int|mixed|null|string
 */
function importFilter($data)
{
    if($data === false){
        return 0;
    }
    //设置过滤规则
    $filter = 'htmlspecialchars';
    if(is_array($data)){
        sort($data);//排序
        $data = serialize($data);
    }
    $filters = explode(',', $filter);

    if (is_array($filters)) {
        foreach ($filters as $filter) {
            if (function_exists($filter)) {
                $data = is_array($data) ? array_map_recursive($filter, $data) : $filter($data); // 参数过滤
            } else {
                $data = filter_var($data, is_int($filter) ? $filter : filter_id($filter));
                if (false === $data) {
                    return null;
                }
            }
        }
    }
    return str_replace("'",'"',$data);
}

/**
 * 从数据库拿数据转义
 * @param $data
 * @return array|int|mixed|null|string
 */
function outportFilter($data)
{

    $filter = 'stripslashes,htmlspecialchars_decode';
//    $filter = 'stripslashes,htmlspecialchars_decode,strip_tags';
    $filters = explode(',', $filter);
    if (is_array($filters)) {
        foreach ($filters as $filter) {
            if (function_exists($filter)) {
                $data = is_array($data) ? array_map_recursive($filter, $data) : $filter($data); // 参数过滤
            } else {
                $data = filter_var($data, is_int($filter) ? $filter : filter_id($filter));
                if (false === $data) {
                    return null;
                }
            }
        }
    }
    return $data;
}


/**
 * 将数据库的序列化内容样式调整为: xx/xx/xx/xx 格式
 * @param $data
 * @return string
 */
function formatSeqData($data)
{
    $str="";
    $data  = $data ? unserialize(outportFilter($data)) : [];
    //调整格式
    for($i=0;$i<count($data);$i++){
        $str .= $data[$i];
        if($i==count($data)-1){
            break;
        }
        $str .="/";
    }
   return $str;
}

/**
 * 过滤两个标记之间的字符串
 * @param $keywork
 * @param string $mark1
 * @param string $mark2
 * @return mixed
 */
function removeDoubleStr($keywork, $mark1 = '@', $mark2 = '@')
{
    if(!is_string($keywork)){
        recordAMSLog(__FILE__.__LINE__."不支持的类型".var_export($keywork,true));
        return $keywork;
    }
    //记录
    static $record = array();

    getNeedBetween($keywork, $mark1, $mark2, $record);
    return str_replace($record,'',$keywork);
}

//获取两个字符串之间的字符串
/**
 * 获取两个标记之间的代码
 * @param $keywork
 * @param $mark1
 * @param $mark2
 * @param $record
 * @return bool
 */
function getNeedBetween($keywork, $mark1, $mark2, &$record)
{

    $i = mb_strpos($keywork, $mark1);//第一个标记出现的位置
    if ($i === false) {
        return false;//没有找到第一个标记
    }
    $keywork2 = mb_substr($keywork, $i + 1);
    $y = mb_strpos($keywork2, $mark2);//第一个标记与第二个标记中间的字符串
    if ($y === false) {
        return false;//没有找到第二个标记
    }
    $msg = mb_substr($keywork2, 0, $y + 1);
    $bet = $mark1 . $msg;
    if (!in_array($bet, $record)) {
        $record[] = $bet;
    }
    //继续监测下面的代码
    $keywork = mb_substr($keywork2, $y + 1);
    getNeedBetween($keywork, $mark1, $mark2, $record);
}




/**
 * 判断是否都是数字
 * @param $num
 * @return bool
 */
function isAllNum($num)
{
    if (is_numeric($num)) {
        return true;
    } else {
        return false;
    }
}

/**
 * 长度校验
 * @param $data
 * @return bool
 */
function lengthCheck($data) {
    if(strlen((round(floatval($data),4)))>9 || (round(floatval($data),4))>100000) {
        return true;
    }else {
        return false;
    }
}


/**
 * 判断是否都是英文
 * @param $str
 * @return bool
 */
function isAllEnglish($str)
{
    if(preg_match("/^[a-zA-Z\s]+$/",$str)){
        return true;
    }else{
        return false;
    }
}

/**
 * 将字符串中的中文逗号转换为英文逗号
 * @param $str
 * @return null|string|string[]
 */
function transformComma($str)
{
    return str_replace('，',',',$str);
}

/**
 * @param $str 要过滤的字符串
 * @param $tags 不要过滤的标签
 * @return string
 */
function strip_other_tags($str,$tags = null)
{
    //设置不需要过滤的标签
    if(empty($tags)){
        //基本
        $tags = "<title>";
        //文本
        $tags .= "<h1><h2><h3><h4><h5><h6><b><strong><i><em><a><sub><sup><p><span><div>";
        //图形
        $tags .= "<img><hr><del>";
        //表格
        $tags .= "<table><th><tr><td>";
        //其他 不需要过滤的标签请在这里补充完整
        $tags .= "";
    }
    if(is_array($tags)){
        $tags = implode('',$tags);
    }
    return strip_tags($str,$tags);
}

/**
 * 字符串截取最后一个“/”后面的全部字符串
 * @param $str
 * @return string
 */
function getLastContent($str)
{
    $str =substr($str,strripos($str,"/")+1);
    return $str;
}

/**
 * 将数组里面的值转为int,float类型
 * @param $data
 * @return array|void
 */
function intArrayVal($data)
{
    if(!is_array($data)){
        return;
    }
    foreach ($data as $key=>$val)
    {
        //判断字符串是否含有点
        if(strpos($val,'.')) {
            $data[$key] = floatval($val);
        }else{
            $data[$key] = intval($val);
        }
    }
    return $data;
}